package com.jds.test.websocket;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.ChannelGroupFuture;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by sunyuming on 18/9/3.
 */
public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<String> {

    private static final String SPLIT = ":\t";

    private static final ChannelGroup group = new DefaultChannelGroup("ChannelGroups", GlobalEventExecutor.INSTANCE);
    private static final ConcurrentHashMap<String, Channel> userChannel = new ConcurrentHashMap<String, Channel>();

    private static String getOnine() {
        StringBuilder stringBuilder = new StringBuilder(group.size() * 20);
        String online = "[在线用户]";
        stringBuilder.append(online);
        for(Channel channel : group) {
            String name = channel.attr(HttpRequestHandler.key).get();
            stringBuilder.append(" " + name);
        }
        return stringBuilder.toString();
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt == WebSocketServerProtocolHandler.ServerHandshakeStateEvent.HANDSHAKE_COMPLETE) {

            // 移除性能更加
            ctx.pipeline().remove(HttpRequestHandler.class);
            String userName = ctx.channel().attr(HttpRequestHandler.key).get();
            Channel old = userChannel.put(userName, ctx.channel());
            if(old != null) {
                group.remove(old);
                System.out.println(old.attr(HttpRequestHandler.key).get() + SPLIT + "［切换设备］");
                ChannelFuture channelFuture = old.writeAndFlush("您的账户在其它地方登陆");
                channelFuture.addListener(ChannelFutureListener.CLOSE);
            }

            ctx.writeAndFlush("－＝＝＝＝＝登录成功＝＝＝＝＝－");

            String up = userName + SPLIT + "［上线］";
            System.out.println(up);
            group.writeAndFlush(up);

            group.add(ctx.channel());

            String online = getOnine();
            System.out.println(online);
            group.writeAndFlush(online);

        }else if (evt instanceof IdleStateEvent) {
            // 2*4+1 s内读空闲时，关掉连接，表示客户端不可见了
            IdleStateEvent evnet = (IdleStateEvent) evt;
            if (evnet.state().equals(IdleState.READER_IDLE)) {
                ctx.close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        String userName = ctx.channel().attr(HttpRequestHandler.key).get();
        userChannel.remove(userName);
        String down = userName + SPLIT + "［下线］";
        System.out.println(down);
        group.writeAndFlush(down);
        group.remove(ctx.channel());

        String online = getOnine();
        System.out.println(online);
        group.writeAndFlush(online);

        super.channelInactive(ctx);
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        // 这一段也是错的，书上因为是直接write，因此要retain，这里已经新建了String实例，所以retain会造成内存泄漏
//        String send = ctx.channel().attr(HttpRequestHandler.key).get() + SPLIT + msg.retain().text();
//        System.out.println(send);
//        group.writeAndFlush(new TextWebSocketFrame(send));

        if("HeartBeat".equals(msg)) {
            // 心跳只给自己发
            ctx.writeAndFlush(msg);
        } else {
            // 聊天发给所有人
            String send = ctx.channel().attr(HttpRequestHandler.key).get() + SPLIT + msg;
            System.out.println(send);
            group.writeAndFlush(send);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        cause.printStackTrace();
        ctx.close();
    }

}
